package org.waddy.framework.pub.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.RandomAccessFile;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 项目名称：BaseUtils
 * 类名称：FileUtil
 * 类描述：文件工具类<br>
 * 功能列表：<br>
 * 1.读取文件内容：readFileByLines(String fileName)<br>
 * 2.文件过滤查找:getFilepathMap<br>
 * 3.文件复制:copy<br>
 * @author 张大朋
 * @since 2011-8-29 下午06:28:56
 * @version
 */
public class FileUtil {
	private static List<String> fileList = new ArrayList<String>();
	private static Map<String, String> filepathMap = new HashMap<String, String>();

	public static void main(String[] args) throws IOException {
		Map<String, String> filepathMap = FileUtil.getFilepathMap(
				"G:\\WorkSpace\\Library", "jar", true);
		if (filepathMap.isEmpty()) {
			System.out.println("没有符合要求的文件");
		} else {
			System.out.println(filepathMap);
		}
	}

	/************************* 读取文件内容 ********************************/

	/**
	 * 以行为单位读取文件，常用于读面向行的格式化文件
	 * 
	 * @param fileName
	 *            文件名
	 */
	public static String readFileByLines(String fileName) {
		StringBuffer buffer = new StringBuffer();
		File file = new File(fileName);
		BufferedReader reader = null;
		try {
			//以行为单位读取文件内容，一次读一整行
			reader = new BufferedReader(new FileReader(file));
			String tempString = null;
			int line = 1;
			// 一次读入一行，直到读入null为文件结束
			while ((tempString = reader.readLine()) != null) {
				// 显示行号
				// System.out.println("line " + line + ": " + tempString);
				buffer.append(tempString + "\n");
				line++;
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
				}
			}
		}
		return buffer.toString();
	}

	/************************* 写入文件内容 ********************************/
	
	/**
	 * 将String写入文件，采用指定编码格式
	 * @param content 大量文字内容,比如HTML代码
	 * @param charsetName 编码格式名称，如：UTF-8
	 * @param fileName 文件全路径名
	 */
	public static void writeFileByCoding(String content, String charsetName, String fileName){
		final File file = new File(fileName);
		try {
			//如果文件不存在,则建立
			if (!file.exists()){  
				new File(file.getParent()).mkdirs();//若目录不存在，则创建
				file.createNewFile();//创建文件
			}  
			final Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charsetName));       
			out.write(content);  
			out.flush();  
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/************************* 文件查找 ********************************/

	/**
	 * @param path
	 *            文件路径
	 * @param suffix
	 *            后缀名
	 * @param isdepth
	 *            是否遍历子目录
	 * @return
	 */
	public static List<String> getFileList(String path, String suffix,
			boolean isdepth) {
		fileList.clear();
		File file = new File(path);
		return listFile(file, suffix, isdepth);
	}

	/**
	 * @param path
	 *            文件路径
	 * @param suffix
	 *            后缀名
	 * @param isdepth
	 *            是否遍历子目录
	 * @return
	 */
	public static Map<String, String> getFilepathMap(String path,
			String suffix, boolean isdepth) {
		filepathMap.clear();
		File file = new File(path);
		return mapFile(file, suffix, isdepth);
	}

	public static List<String> listFile(File f, String suffix, boolean isdepth) {
		// 是目录，同时需要遍历子目录
		if (f.isDirectory() && isdepth == true) {
			File[] t = f.listFiles();
			for (int i = 0; i < t.length; i++) {
				listFile(t[i], suffix, isdepth);
			}
		} else if (f.isDirectory() && isdepth != true) {
			File[] t = f.listFiles();
			for (int i = 0; i < t.length; i++) {
				getFilePath(t[i], suffix);
			}
		} else {
			getFilePath(f, suffix);
		}

		return fileList;
	}

	public static Map<String, String> mapFile(File f, String suffix,
			boolean isdepth) {
		// 是目录，同时需要遍历子目录
		if (f.isDirectory() && isdepth == true) {
			File[] t = f.listFiles();
			for (int i = 0; i < t.length; i++) {
				mapFile(t[i], suffix, isdepth);
			}
		} else if (f.isDirectory() && isdepth != true) {
			File[] t = f.listFiles();
			for (int i = 0; i < t.length; i++) {
				getFilepathMap(t[i], suffix);
			}
		} else {
			getFilepathMap(f, suffix);
		}

		return filepathMap;
	}

	private static String getFilePath(File f, String suffix) {
		String filePath = f.getAbsolutePath();
		if (suffix != null) {
			int begIndex = filePath.lastIndexOf(".");// 最后一个.(即后缀名前面的.)的索引
			String tempsuffix = "";

			if (begIndex != -1)// 防止是文件但却没有后缀名结束的文件
			{
				tempsuffix = filePath
						.substring(begIndex + 1, filePath.length());
			}

			if (tempsuffix.equalsIgnoreCase(suffix)) {
				fileList.add(filePath);
			}
		} else {
			// 后缀名为null则为所有文件
			fileList.add(filePath);
		}
		return filePath;
	}

	private static Map<String, String> getFilepathMap(File f, String suffix) {
		String filePath = f.getAbsolutePath();
		if (suffix != null) {
			int begIndex = filePath.lastIndexOf(".");// 最后一个.(即后缀名前面的.)的索引
			String tempsuffix = "";

			if (begIndex != -1)// 防止是文件但却没有后缀名结束的文件
			{
				tempsuffix = filePath
						.substring(begIndex + 1, filePath.length());
			}

			if (tempsuffix.equalsIgnoreCase(suffix)) {
				filepathMap.put(f.getName(), filePath);
			}
		} else {
			// 后缀名为null则为所有文件
			filepathMap.put(f.getName(), filePath);
		}
		return filepathMap;
	}

	/************************* 文件复制 *************************/

	/**
	 * 对外公开
	 */
	public static void copy(File f1, File f2) throws IOException{
		if(f2.isDirectory()){
			String newFileFullName = f2.getAbsolutePath()+System.getProperty("file.separator")+f1.getName();
			f2 = new File(newFileFullName);
		}
		copy1(f1,f2);
	}

	/**
	 * 在测试结果中看到 传统方式,和管道向管道传输是最快的
	 */
	
	/**
	 * 传统方式的文件拷贝
	 */
	private static long copy1(File f1, File f2) throws IOException {
		long time = new Date().getTime();
		int length = 2097152;
		FileInputStream in = new FileInputStream(f1);
		FileOutputStream out = new FileOutputStream(f2);
		byte[] buffer = new byte[length];
		while (true) {
			int ins = in.read(buffer);
			if (ins == -1) {
				in.close();
				out.flush();
				out.close();
				return new Date().getTime() - time;
			} else
				out.write(buffer, 0, ins);
		}
	}
	
	/**
	 * 使用NIO中的管道到管道传输 
	 */
	public static long copy2(File f1,File f2) throws Exception{
        long time=new Date().getTime();
        int length=2097152;
        FileInputStream in=new FileInputStream(f1);
        FileOutputStream out=new FileOutputStream(f2);
        FileChannel inC=in.getChannel();
        FileChannel outC=out.getChannel();
        int i=0;
        while(true){
            if(inC.position()==inC.size()){
                inC.close();
                outC.close();
                return new Date().getTime()-time;
            }
            if((inC.size()-inC.position())<20971520)
                length=(int)(inC.size()-inC.position());
            else
                length=20971520;
            inC.transferTo(inC.position(),length,outC);
            inC.position(inC.position()+length);
            i++;
        }
    }
	
	/**
	 * 内存文件景象写(读文件没有使用文件景象,有兴趣的可以回去试试,,我就不试了,估计会更快) 
	 */
	public static long copy3(File f1,File f2) throws Exception{
        long time=new Date().getTime();
        int length=2097152;
        FileInputStream in=new FileInputStream(f1);
        RandomAccessFile out=new RandomAccessFile(f2,"rw");
        FileChannel inC=in.getChannel();
        MappedByteBuffer outC=null;
        MappedByteBuffer inbuffer=null;
        byte[] b=new byte[length];
        while(true){
            if(inC.position()==inC.size()){
                inC.close();
                outC.force();
                out.close();
                return new Date().getTime()-time;
            }
            if((inC.size()-inC.position())<length){
                length=(int)(inC.size()-inC.position());
            }else{
                length=20971520;
            }
            b=new byte[length];
            inbuffer=inC.map(MapMode.READ_ONLY,inC.position(),length);
            inbuffer.load();
            inbuffer.get(b);
            outC=out.getChannel().map(MapMode.READ_WRITE,inC.position(),length);
            inC.position(b.length+inC.position());
            outC.put(b);
            outC.force();
        }
    }
	
	/**
	 * 管道对管道 
	 */
	 public static long copy4(File f1,File f2) throws Exception{
	        long time=new Date().getTime();
	        int length=2097152;
	        FileInputStream in=new FileInputStream(f1);
	        FileOutputStream out=new FileOutputStream(f2);
	        FileChannel inC=in.getChannel();
	        FileChannel outC=out.getChannel();
	        ByteBuffer b=null;
	        while(true){
	            if(inC.position()==inC.size()){
	                inC.close();
	                outC.close();
	                return new Date().getTime()-time;
	            }
	            if((inC.size()-inC.position())<length){
	                length=(int)(inC.size()-inC.position());
	            }else
	                length=2097152;
	            b=ByteBuffer.allocateDirect(length);
	            inC.read(b);
	            b.flip();
	            outC.write(b);
	            outC.force(false);
	        }
	    }
}
